/*
 * addon_ddlutil.cpp
 *
 *  Created on: 2010-1-7
 *      Author: gavinkwoe
 */

#include "addon_features.h"

#if (__ADDON_TARGET__ == __TARGET_SYMBIAN)

#include "addon_std.h"
#include "addon_mem.h"
#include "addon_objbase.h"
#include "addon_dllutil.h"
#include "QOsBase.h"

//#include <e32const.h>
//#include <e32std.h>

/*************************************************************************
* GUID
*************************************************************************/

ADDON_DEFINED_GUID( IAddonDLL, 1, "D7597E4E-25B4-456b-B214-70E32FFF6148" )

/*************************************************************************
* STRUCTURE
*************************************************************************/

struct __struct_addon_DLL_data;
typedef struct __struct_addon_DLL_data		addon_DLL_data_t;
typedef struct __struct_addon_DLL_data *	addon_DLL_data_ptr_t;

/*************************************************************************
* DEFINITION
*************************************************************************/

struct __struct_addon_DLL_data
{
	unsigned long	ref_cnt;	// reference count
	unsigned long	is_load;
#ifdef PLATFORM_SYMBIAN
	RLibrary *		library;	// DLL resource handle
#endif
};

/*************************************************************************
* LOCAL FUNCTIONS
*************************************************************************/

unsigned long	__CDLL_Construct( ADDON_REF(IObject) thiz, void * usr_data );
unsigned long	__CDLL_Destruct( ADDON_REF(IObject) thiz );
unsigned long	__CDLL_AddRef( ADDON_REF(IObject) thiz );
unsigned long	__CDLL_Release( ADDON_REF(IObject) thiz );

unsigned long	__CDLL_IsLoaded( ADDON_REF(IObject) thiz, unsigned long * is_load );
unsigned long	__CDLL_Load( ADDON_REF(IObject) thiz, unsigned short * fname );
unsigned long	__CDLL_Unload( ADDON_REF(IObject) thiz );
unsigned long	__CDLL_GetProcAddr( ADDON_REF(IObject) thiz, unsigned long index, void ** ppaddr );
// 
// const void * const __coclass_vtbl[] =
// {
// 	// IObject
// 	(void *)__CDLL_Construct,
// 		(void *)__CDLL_Destruct,
// 		(void *)__CDLL_AddRef,
// 		(void *)__CDLL_Release,
// 		
// 		// IAddonDLL
// 		(void *)__CDLL_IsLoaded,
// 		(void *)__CDLL_Load,
// 		(void *)__CDLL_Unload,
// 		(void *)__CDLL_GetProcAddr
// };
// 
// const addon_coclass_desc_t __coclass_desc =
// {
// 	(unsigned char *)__coclass_vtbl,
// 		(unsigned long)sizeof( addon_DLL_data_t )
// 	};

/*************************************************************************
* IMPLEMENTATION
*************************************************************************/

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __CDLL_Construct( ADDON_REF(IObject) thiz, void * usr_data )
{
	addon_DLL_data_ptr_t obj_data = (addon_DLL_data_ptr_t)ADDON_GET_DATA( thiz );

	ADDON_UNUSED( usr_data );
	
	if ( NULL == obj_data )
		return ADDON_FAILED;

	obj_data->ref_cnt = 1;
	obj_data->is_load = ADDON_FALSE;
	
#ifdef PLATFORM_SYMBIAN
	obj_data->library = new RLibrary;
	if ( NULL == obj_data->library )
		return ADDON_FAILED;
#endif
	return ADDON_OK;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __CDLL_Destruct( ADDON_REF(IObject) thiz )
{
	addon_DLL_data_ptr_t obj_data = (addon_DLL_data_ptr_t)ADDON_GET_DATA( thiz );

	if ( NULL == obj_data )
		return ADDON_FAILED;

#ifdef PLATFORM_SYMBIAN	
	if ( NULL != obj_data->library )
	{
		__CDLL_Unload( thiz );

		delete obj_data->library;
		obj_data->library = NULL;
	}
#endif	
	return ADDON_OK;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __CDLL_AddRef( ADDON_REF(IObject) thiz )
{
	addon_DLL_data_ptr_t obj_data = (addon_DLL_data_ptr_t)ADDON_GET_DATA( thiz );

	if ( NULL == obj_data )
		return ADDON_FAILED;
	
	obj_data->ref_cnt++;
	return ADDON_OK;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __CDLL_Release( ADDON_REF(IObject) thiz )
{
	addon_DLL_data_ptr_t obj_data = (addon_DLL_data_ptr_t)ADDON_GET_DATA( thiz );

	if ( NULL == obj_data )
		return ADDON_FAILED;
	
	obj_data->ref_cnt -= 1;

	if ( 0 == obj_data->ref_cnt )
	{
		addon_obj_delete( (void *)thiz );
	}
	
	return ADDON_OK;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __CDLL_IsLoaded( ADDON_REF(IObject) thiz, unsigned long * is_load )
{
	addon_DLL_data_ptr_t obj_data = (addon_DLL_data_ptr_t)ADDON_GET_DATA( thiz );

	if ( NULL == is_load )
		return ADDON_FAILED;
	
	*is_load = obj_data->is_load;
	return ADDON_OK;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __CDLL_Load( ADDON_REF(IObject) thiz, unsigned short * fname )
{
#ifdef PLATFORM_SYMBIAN
	TInt	ret_val;
	TPtrC16 temp_str( (const TUint16 *)fname );
	
	addon_DLL_data_ptr_t obj_data = (addon_DLL_data_ptr_t)ADDON_GET_DATA( thiz );

	__CDLL_Unload( thiz );
	
	ret_val = obj_data->library->Load( temp_str );
	if ( KErrNone == ret_val )
	{
		obj_data->is_load = ADDON_TRUE;
		return ADDON_OK;
	}
#endif	
	return ADDON_FAILED;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __CDLL_Unload( ADDON_REF(IObject) thiz )
{
	addon_DLL_data_ptr_t obj_data = (addon_DLL_data_ptr_t)ADDON_GET_DATA( thiz );
	
	if ( ADDON_FALSE != obj_data->is_load )
	{
#ifdef PLATFORM_SYMBIAN
		obj_data->library->Close();
#endif
		obj_data->is_load = ADDON_FALSE;
	}
	
	return ADDON_OK;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
unsigned long __CDLL_GetProcAddr( ADDON_REF(IObject) thiz, unsigned long index, void ** ppaddr )
{
#ifdef PLATFORM_SYMBIAN
	TLibraryFunction func_addr;
	addon_DLL_data_ptr_t obj_data = (addon_DLL_data_ptr_t)ADDON_GET_DATA( thiz );

	if ( NULL == ppaddr )
		return ADDON_FAILED;
	
	if ( ADDON_FALSE == obj_data->is_load )
		return ADDON_FAILED;

	func_addr = obj_data->library->Lookup( index );
	*ppaddr = (void *)func_addr;
#endif	
	return ADDON_OK;
}

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
ADDON_EXPORT ADDON_REF(IObject) addon_create_DLL( void * reserved )
{
	//static const 
	void * __coclass_vtbl[8];// =
	//{
		// IObject
	int i=0;
	__coclass_vtbl[i++] =		(void *)__CDLL_Construct;
	__coclass_vtbl[i++] =		(void *)__CDLL_Destruct;
	__coclass_vtbl[i++] =			(void *)__CDLL_AddRef;
	__coclass_vtbl[i++] =			(void *)__CDLL_Release;
			
			// IAddonDLL
	__coclass_vtbl[i++] =			(void *)__CDLL_IsLoaded;
	__coclass_vtbl[i++] =			(void *)__CDLL_Load;
	__coclass_vtbl[i++] =			(void *)__CDLL_Unload;
	__coclass_vtbl[i++] =			(void *)__CDLL_GetProcAddr;
	//};
	
// 	static const addon_coclass_desc_t __coclass_desc =
// 	{
// 		(unsigned char *)__coclass_vtbl,
// 			(unsigned long)sizeof( addon_DLL_data_t )
// 	};
	addon_coclass_desc_t __coclass_desc;
	
	__coclass_desc.vtbl_size	= (unsigned long)sizeof(__coclass_vtbl);
	__coclass_desc.vtbl_funcs	= (unsigned char *)__coclass_vtbl;
	__coclass_desc.priv_size	= (unsigned long)sizeof(addon_DLL_data_t);

	return ( ADDON_REF(IObject) )addon_obj_new( (addon_coclass_desc_ptr_t)&__coclass_desc, reserved );
}


#else	// #if (__ADDON_TARGET__ == __TARGET_SYMBIAN)

/*************************************************************************
* DESCRIPTION
*	$$__FUNC_DESC__$$
*************************************************************************/
ADDON_EXPORT ADDON_REF(IObject) addon_create_DLL( void * reserved )
{
	ADDON_UNUSED( reserved );
	return NULL;
}

#endif	// #if (__ADDON_TARGET__ == __TARGET_SYMBIAN)
